/* 常用方法
---------------------------------------------------------------- */
/**
 * 深度克隆
 * 例 let res = $util.deepClone({data:data})
 * @param {Any} data  数据,可String|Number|Array|Object|ObjectArray|Function
 * @returns {Any} 克隆目标
 */
export function deepClone({ data }: { data?: any }) {
  if (!data) return console.error({ message: '参数有误', function: deepClone })

  // 只有对象和数组才进行深度拷贝
  if (!data && typeof data !== 'object') return data

  // 创建新的 Array|Object
  const target: any = data.constructor === Array ? [] : {}
  Object.keys(data).forEach((key) => {
    // 当拷贝的对象中还有数组或是对象时进行递归，克隆它们中的内容，直到递归完所有数组或对象为止
    if (data[key] && typeof data[key] === 'object') {
      target[key] = deepClone({ data: data[key] })
    } else {
      target[key] = data[key]
    }
  })

  return target
}

/**
 * 延时 延迟、等待一段时间再继续执行(bug:单线程)
 * 例 $util.sleep({time:1000})
 * @param {Number} time 单位ms,默认2000
 */
export function sleep({ time = 1000 }: { time?: number }) {
  const end = new Date().getTime() + time
  while (new Date().getTime() < end) {
    continue
  }
}

/**
 * 延时 异步 搭配 await使用
 * 例 await $util.sleepAsync({time:1000})
 * @param {Number} time 单位ms,默认1000
 */
export function sleepAsync({ time = 1000 }: { time?: number }) {
  return new Promise((resolve) => setTimeout(resolve, time))
}

/**
 * 防抖 结束一段时间后执行
 * 例 await $util.debounce({time:1000})
 * @param {Number} time 单位ms,默认1000
 * @param {String} id 为了防止同时执行多个防抖操作
 */
export function debounce({ time = 1000, id }: { time?: number; id?: string }) {
  return new Promise((resolve) => {
    const key = id ? `timer_debounce_${id}` : 'timer_debounce'
    clearTimeout((window as any)[key])
    ;(window as any)[key] = setTimeout(() => resolve(false), time)
  })
}

/**
 * 节流 每隔一段时间执行一次
 * 例 if( await $util.throttle({time:1000}) ) return
 * @param {Number} time 单位ms,默认2000
 * @param {String} id 为了防止同时执行多个节流操作
 */
export function throttle({ time = 2000, id }: { time?: number; id?: string }) {
  const key = id ? `Has_throttle_${id}` : 'Has_throttle'
  if ((window as any)[key]) return true
  ;(window as any)[key] = true
  setTimeout(() => ((window as any)[key] = false), time)
  return false
}
